using System;
using System.Web;

namespace tvgrabau
{	
	public static class YTVParser
	{
		private static string[] STime;
		private static string[] ETime;

        /// <summary>
        /// Converts the specified HTML string into a Programme.
        /// </summary>	
		public static Programme GatherDetails(string s)
		{
			s = s.Replace("if (window.___ww) ___ww_flush();", "");
			Programme p = new Programme();
			
			p.Title = HttpUtility.HtmlEncode(ParseName(s));
			if (p.Title == "~~~~~~ ERROR ~~~~~~")
			{
				p.Title = "";
				Console.WriteLine("ERROR! Here comes the source: ");
				Console.WriteLine(s);
				p.Type = ProgrammeType.Errored;
				return p;
			}
			
			p.EpisodeName = HttpUtility.HtmlEncode(ParseEpisode(s));
			ParseInitialTimes(s);
			p.TimeEnd = ParseEndTime();
			p.TimeStart = ParseStartTime();
			p.ChannelName = ParseChannel(s);
			if (!MainClass.options.NoDescriptions)
			{
			    p.Description = HttpUtility.HtmlEncode(ParseDesc(s));
			}
			p.Category = HttpUtility.HtmlEncode(ParseGenre(s));
			p.Classification = ParseRating(s);
			p.Country = ParseCountry(s);
			p.Year = ParseYear(s);
			p.Cast = HttpUtility.HtmlEncode(ParseCast(s));
			
			string i = LoadGeneral(s);
			p.HDTV = Contains(i, "High Definition");
			p.Premiere = Contains(i, "Premiere");
			p.Repeat = Contains(i, "Repeat");
			p.Teletext = Contains(i, "Closed Captions");
			p.Widescreen = Contains(i, "Widescreen");
			p.Final = Contains(i, "Final");
					
			if (s.IndexOf("Find more info on this movie with") > -1)
			{
				p.Type = ProgrammeType.Movie;
			}
			else if (p.Category.IndexOf("Sport") > -1)
			{
				p.Type = ProgrammeType.Sports;
				p.Category = p.Category.Replace("Sport/", "");
				p.Category = p.Category.Replace("Sport", "");
			}
			
			if (p.Type == ProgrammeType.Movie)
			{
				p.Score = GetScore(p.Title, p.Year);
			}
			
			/*Console.WriteLine("Program: {0}", p.Title);
			Console.WriteLine("Start time: {0}", p.TimeStart.ToString());
			Console.WriteLine(" End  time: {0}", p.TimeEnd.ToString());
			Console.WriteLine();*/
			
			return p;
		}
		
		private static string ParseName(string programInfo)
		{
			string ShowName = "";
            int shownamestart = programInfo.IndexOf("<h1>");
            if (shownamestart != -1)
            {          
            	shownamestart += 4;
            	int shownameend = YourTV.findNextChar('<', programInfo, shownamestart);
            	ShowName = programInfo.Substring(shownamestart, shownameend - shownamestart);
        	}
        	else
        	{
        		// Send back an error string
        		ShowName = "~~~~~~ ERROR ~~~~~~";
        	}
        	
        	return ShowName;
		}
		
		private static string ParseEpisode(string programInfo)
		{
			string r = null;
			int epnamestart = programInfo.IndexOf("<div><h2><span style=\"font-weight:normal\"></span>");
            if (epnamestart != -1)
            {
                epnamestart += 49;
                int epnameend = YourTV.findNextChar('<', programInfo, epnamestart);
                string EpisodeName = programInfo.Substring(epnamestart, epnameend - epnamestart);
                EpisodeName = EpisodeName.Trim();
                r = EpisodeName;
            }
            
            return r;
		}
		
		private static string ParseChannel(string programInfo)
		{
			string r = null;
			int channelstart = programInfo.IndexOf("<span class=\"pop_chan\">");
            if (channelstart != -1)
            {
            	channelstart += 23;
            	int channelend = YourTV.findNextChar('<', programInfo, channelstart);
            	string ChannelName = programInfo.Substring(channelstart, channelend - channelstart);
            	r = ChannelName;
            }
            
            return r;
		}
		
		private static string ParseDesc(string programInfo)
		{
			string r = null;	
			int startdivnoshade = programInfo.IndexOf("<hr noshade>");
            int startdescription = programInfo.IndexOf("<div>", startdivnoshade);
            if (startdescription != -1 && startdivnoshade != -1)
            {
            	startdescription += 5;
            	int descriptionend = YourTV.findNextChar('<', programInfo, startdescription);
            	string ProgramDescription = programInfo.Substring(startdescription, descriptionend - startdescription);
            	r = ProgramDescription;
            }
            
            return r;
		}
		
		private static string ParseGenre(string programInfo)
		{
			string r = null;
			int startgenredef = programInfo.IndexOf("<strong>Genre:");
            int startgenre = programInfo.IndexOf("<td valign=\"top\">", startgenredef);
            if (startgenre != -1 && startgenredef != -1)
            {
            	startgenre += 17;
            	int endgenre = YourTV.findNextChar('<', programInfo, startgenre);
            	string Genre = programInfo.Substring(startgenre, endgenre - startgenre).Trim();
            	r = Genre;
            }
            
            return r;
		}
		
		private static string ParseRating(string programInfo)
		{
			string r = null;
			int startratedef = programInfo.IndexOf("<strong>Rating:");
            int startrate = programInfo.IndexOf("<strong>", startratedef + 15);
            if (startrate != -1 && startratedef != -1)
            {
            	startrate += 8;
            	int endrate = YourTV.findNextChar('<', programInfo, startrate);
            	string Rating = programInfo.Substring(startrate, endrate - startrate).Trim();
            	r = Rating;
            }
            
            return r;
		}
		
		private static string ParseCountry(string programInfo)
		{
			string r = null;
			int startcountdef = programInfo.IndexOf("<strong>Country:");
            int startcount = programInfo.IndexOf("<td valign=\"top\">", startcountdef + 16);
            if (startcount != -1 && startcountdef != -1)
            {
            	startcount += 17;
            	int endcount = YourTV.findNextChar('<', programInfo, startcount);
            	string Country = programInfo.Substring(startcount, endcount - startcount).Trim();
            	r = Country;
            }
            
            return r;
		}
		
		private static string ParseYear(string programInfo)
		{
			string r = null;
		    int startyeardef = programInfo.IndexOf("<strong>Year:");
            int startyear = programInfo.IndexOf("<td valign=\"top\">", startyeardef + 13);
            if (startyear != -1 && startyeardef != -1)
            {
            	startyear += 17;
            	int endyear = YourTV.findNextChar('<', programInfo, startyear);
            	string Year = programInfo.Substring(startyear, endyear - startyear).Trim();
            	r = Year;
            }
            
            return r;
		}
		
		private static string ParseCast(string programInfo)
		{
			string r = null;
			int startcastdef = programInfo.IndexOf("<strong>Cast:");
            int startcast = programInfo.IndexOf("<td valign=\"top\">", startcastdef + 13);
            if (startcast != -1 && startcastdef != -1)
            {
            	startcast += 17;
            	int endcast = YourTV.findNextChar('<', programInfo, startcast);
            	string CastListStr = programInfo.Substring(startcast, endcast - startcast).Trim();
            	r = CastListStr;
            }
            
            return r;
		}
		
		private static void ParseInitialTimes(string programInfo)
		{
			int starttimestart = programInfo.IndexOf("<td><h3><div>");
            if (starttimestart != -1)
            {
            	starttimestart += 13;
            	
            	int starttimeend = YourTV.findNextChar('_', programInfo, starttimestart);
            	string Times = programInfo.Substring(starttimestart, starttimeend - starttimestart).Replace(" ", "").Replace("\t", "").Replace("\r", "").Replace("\n", "");
            	Times = Times.Remove(Times.Length - 16, 16);

            	char[] firstSplit = { '!' };
            	char[] secondSplit = { '+' };
            	string[] TimesArray = Times.Split(firstSplit);
            	int javascriptone_start = YourTV.findNextChar('(', TimesArray[0], 0) + 1;
            	int javascriptone_end = YourTV.findNextChar('<', TimesArray[0], javascriptone_start) - 2;
            	int javascripttwo_start = YourTV.findNextChar('(', TimesArray[1], 0) + 1;
            	int javascripttwo_end = YourTV.findNextChar('<', TimesArray[1], javascripttwo_start) - 2;
            	string javascriptone = TimesArray[0].Substring(javascriptone_start, javascriptone_end - javascriptone_start).Replace("'", "");
            	string javascripttwo = TimesArray[1].Substring(javascripttwo_start, javascripttwo_end - javascripttwo_start).Replace("'", "");

            	STime = javascriptone.Split(secondSplit);
            	ETime = javascripttwo.Split(secondSplit);
            }
            
		}
		
		private static string LoadGeneral(string programInfo)
		{
		    int startotherdef = programInfo.IndexOf("<strong>Other:");
            int startother = programInfo.IndexOf("<td valign=\"top\">", startotherdef);
            if (startother != -1 && startotherdef != -1)
            {
            	startother += 17;
            	int endother = YourTV.findNextChar('/', programInfo, startother);
            	string Other = programInfo.Substring(startother, endother - startother).Trim().Replace("<br>", "").Replace("<", "").Trim().Replace("\t", "").Replace("\r", "").Replace("\n", "");
            	return Other;
            }
            else
            {
            	return "";
            }
		}
		
		private static string GetScore(string pname, string year)
		{
			double ScoreOne = 0;
			double ScoreTwo = 0;
			try
			{
				ScoreOne = double.Parse(getIMDbRating(pname, false, year));
			}
			catch (System.Exception)
			{
				Console.WriteLine("IMDB Failed..");	
			}
			
			try
			{
				ScoreTwo = double.Parse(getRottenInfo(findShowEpListingPage(pname + "+"+year, "rottentomatoes.com")));
			}
			catch (System.Exception)
			{
				Console.WriteLine("RottenTomatoes Failed..");
			}
			
			double RetVal = ScoreOne + ScoreTwo / 2;
			return RetVal.ToString();
		}
		
		public static bool Contains(string i, string s)
		{
			if (i.IndexOf(s) > -1)
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		
		private static DateTime ParseStartTime()
		{
			string startTime = ParseJavascriptTimes(STime);
			return ConvertTime(startTime);
		}
		
		private static DateTime ParseEndTime()
		{
			string stopTime = ParseJavascriptTimes(ETime);
			return ConvertTime(stopTime);
		}
		
		private static string ParseJavascriptTimes(string[] inarray)
        {
        	string characterList = "";
            foreach(string c in inarray)
            {
            	string d = c.Replace("'", "");
            	if (d.StartsWith("String") == false && d.EndsWith(")"))
            	{
            		// Probably m), pm), am)
            		d = d.Replace(")", "");
            		characterList += d;
            	}
            	else if (d.EndsWith(";") == false && d.StartsWith("String") == false)
            	{
            		// Just a number, or a dot (.)
            		characterList += d;
            	}
            	else if (d.StartsWith("String"))
            	{
            		// String.fromCharCode
            		int startValues = YourTV.findNextChar('(', d, 0);
            		int endValues = YourTV.findNextChar(')', d, startValues);
            		string values = d.Substring(startValues + 1, (endValues - startValues) - 1);
            		char[] splitAnother = { '-' };
            		values = values.Replace("(", "").Replace(")", "");
            		string[] nValues = values.Split(splitAnother);
            		int value1 = int.Parse(nValues[0]);
            		int value2 = 0;
            		if (nValues[1].IndexOf("*") > -1)
            		{
            			string[] multi = nValues[1].Split('*');
            			//Console.WriteLine(nValues[1]);
            			int m1 = int.Parse(multi[0]);
            			int m2 = int.Parse(multi[1]);
            			
            			value2 = m1 * m2;
            		}
            		else
            		{
            			value2 = int.Parse(nValues[1]);
            		}
            		int finalValue = value1 - value2;
            			
            		string dstr = new string((Char)finalValue, 1);
            		characterList += dstr;
            	}
            	else if (d.EndsWith(";"))
            	{
            		// Character escape code (&#x5);
            		if (d.IndexOf("x") > -1)
            		{
            			// Hex variation
            			d = d.Replace("x", "").Replace(";", "").Replace("&#", "");
            	    	int dec = int.Parse(d, System.Globalization.NumberStyles.HexNumber);
            			string dstr = new string((Char)dec, 1);
            			characterList += dstr;
            		}
            		else
            		{
            			// Decimal variation
            			d = d.Replace(";", "").Replace(")", "").Replace("&#", "");
            	    	int dec = int.Parse(d);
            			string dstr = new string((Char)dec, 1);
            			characterList += dstr;
            		}
            	}
            	else
            	{
            		// Character escape code (&#x5);
            		if (d.IndexOf("x") > -1)
            		{
            			// Hex variation
            			d = d.Replace("x", "").Replace(";", "").Replace("&#", "").Replace(")", "");
            	    	int dec = int.Parse(d, System.Globalization.NumberStyles.HexNumber);
            			string dstr = new string((Char)dec, 1);
            			characterList += dstr;
            		}
            		else
            		{
            			// Decimal variation
            			d = d.Replace(";", "").Replace(")", "").Replace("&#", "");
            	    	int dec = int.Parse(d);
            			string dstr = new string((Char)dec, 1);
            			characterList += dstr;
            		}
            	}
			}
			return characterList;
		}
		
		private static DateTime ConvertTime(string input)
        {
        	DateTime dt = DateTime.Parse(YourTV.dt.ToShortDateString());
        	string itime = input.Replace(".", ":");
        	if (itime.Length == 3 || itime.Length == 4)
        	{
        		// Time format is 12pm or 7am
        		itime = itime.Insert(itime.Length - 2, ":00 ");
        	}
        	else
        	{
        		// Time format is 10:50am or 6:30pm
        		itime = itime.Insert(itime.Length - 2, " ");
        	}
        	
        	itime = itime.ToUpper();
        	DateTime idt = DateTime.Parse(itime);
        	dt = dt.AddHours((long)idt.Hour);
        	dt = dt.AddMinutes((long)idt.Minute);
        	
        	if (Generator.x == 1 && idt.Hour > 13)
        	{
        		// Item time is probably from yesterday, as it's in
        		// the morning (Period1) and it's a PM time
        		
        		// Let's minus a day (as it's from yesterday)        			
        		dt = dt.Subtract(new TimeSpan(24, 0, 0));
        	}
        		
        	if (Generator.x == 4 && idt.Hour < 13)
        	{
        		// Item time is probably from tomorrow, as it's in
        		// the late-night timeslot (Period4), and it's AM
        		// time.
        		
        		// Add a day (as it's from tomorrow)
        		dt = dt.AddDays(1);
        	}
        	return dt;
        }
        //////////////////////////////////////////////////////////
        /////////////// BELOW IS NOT USED/SUPPORTED //////////////
        //////////////////////////////////////////////////////////
        
        /////////////// IMDB Ratings Stuff /////////////////
        private static string getIMDbRating(string searchStr, bool forceMatch, string _year)
        {        	
        	string ss = searchStr.Replace(" ", "+");
        	string ResultOne = WebManager.GetPage("http://us.imdb.com/find?s=tt&q="+ss);
        	
        	int startResults = ResultOne.IndexOf("<b>Popular Titles</b>");
        	string retVal = "";
        	if (startResults > -1)
        	{
        		retVal = doMiniFind(ResultOne, _year, startResults);
        	}
        	else
        	{
        		// Double check we just didn't get a page that only have Exact Matches
        		int checkResults = ResultOne.IndexOf("<b>Titles (Exact Matches)</b>");
        		if (checkResults > -1)
        		{
        			retVal = doMiniFind(ResultOne, _year, checkResults);
        		}
        		else
        		{
        	
        		// Looks like it was an exact match, find our rating
        		retVal = doMiniRate(ResultOne);
        		}
        	}
        	return retVal;
        }
        
        private static string doMiniFind(string ResultOne, string _year, int startResults)
        {
        		string retVal = "0";
        		bool correctYR = false;
        		int idx = 0;
        		int timeout = 25;
        		int y = 0;
        		while (correctYR == false)
        		{
        			if (timeout == y)
        			{
        				correctYR = true;
        			}
        			else
        			{
	        			// Do another request, but this time exact match
	        			int startID = ResultOne.IndexOf("<a href=\"/title/", startResults + idx) + 16;
	        			// We need to get the string that looks like "ttxxxxxxx"
	        			string titleID = ResultOne.Substring(startID, 9);
	        			string testYR = ResultOne.Substring(ResultOne.IndexOf("</a> ", startID) + 6, 4);
	        			if (testYR.StartsWith(" <a") == false)
	        			{
		        			if (testYR == _year)
		        			{
		        				if (titleID.Length > 0)
		        				{
		        					retVal = doMiniRate(WebManager.GetPage("http://us.imdb.com/title/"+titleID));
			        				correctYR = true;
			        			}			        			//return true;
			        			else
			        			{
			        				correctYR = true;
			        			}
		        			}
		        			else
		        			{
		        				correctYR = false;
		        				idx += (ResultOne.IndexOf("</li>", startID) + 5) - startID;
	        				}
	        			}
	        			
	        			y++;
	        		}
        			
        		}
        		
        		return retVal;
        }
        
        private static string doMiniRate(string inp)
        {
        	int startStars = inp.IndexOf("/ratings\">");
        	string rateValue = "";
        	if (startStars > -1)
        	{
        		int startRate = inp.IndexOf("<b>", startStars) + 3;
        		rateValue = inp.Substring(startRate, 3);
        	}
        	else
        	{
        		rateValue = "0";
        	}
        	
        	decimal ratingInt = decimal.Parse(rateValue);        	
        	return ratingInt.ToString();
        	
        }
        
        /////////// RottenTomatoes Rating stuff //////////////
        
        private static string findShowEpListingPage(string showName, string site)
        {
        	// Returns a valid URI for the episodePage argument of the
        	// 'getEpisodeInfo' method, and the rottenPage argument of the
        	// 'getRottenInfo' method.
        	// Added in 1.5.2
        	
        	// First revision completed 2006-10-28
        	// Second revision completed 2006-10-29
        	
        	string q = showName.Replace(" ", "+").Replace("&", "%26");
        	string r = WebManager.GetPage("http://www.google.com/search?hl=en&q=allintitle%3A&q=site%3A"+site+"&q="+q+"&btnG=Search");
        	
        	string firstResultSearch = "<a class=l href=\"";
        	int startLink = r.IndexOf(firstResultSearch);
        	string rlink = "";
        	if (startLink > -1)
        	{
        		// OK, there's at least one result
        		// Let's get the first..
        		startLink += firstResultSearch.Length;
        		int endLink = r.IndexOf("\"", startLink);
        		
        		// Set rlink (our result string)
        		rlink = r.Substring(startLink, endLink - startLink);
        	}
        	else
        	{
        		// Oh damn, no results.. :(
			// Normally I'd throw an exception, but it's getting to messy now..
        	}
        	
        	return rlink;
        }
        
        private static string getRottenInfo(string rottenPage)
		{
			// Returns the average 'critics' rating, as well as the
			// 'users' rating, off RottenTomatoes.
			// Added in 1.5.2
			
			// First revision completed 2006-10-29
			// Bugs fixed since first revision:
			//	*	Getting the user rating value doesn't depend on
			//		critic's rating success
			//	*	Wrapped int.Parse in try{} block, because there
			//		were some cases where the FormatException would
			//		be thrown - now just fails silently, like IMDb.
			
			double _critic = 0;
			double _users = 0;
			string _retVal = "";
			
			string r = WebManager.GetPage(rottenPage);
			string fstring = "CRITICS <span class=\"subnav_button_percentage\">";
			int frateloc = r.IndexOf(fstring);
			if (frateloc > -1)
			{
				// Get string of % of critics rating
				string frate = r.Substring(frateloc + fstring.Length, 2);
				
				// Find the value (out of 5)
				try
				{
					_critic = double.Parse(frate) / 20;
				}
				// Catch any exception, I'm too lazy to do anything about it..
				catch (System.Exception)
				{
					// Tell the user something bad happened.. ;)
					Console.WriteLine("DEBUG: Some badass parsing happened - critic rating failed");
				}
			}
			else
			{
				//Console.WriteLine("Failed getting critic rating value!");
			}
			
			// Now, go get Users rating
			string sstring = "USERS <span class=\"subnav_button_percentage\">";
			int srateloc = r.IndexOf(sstring);
			if (srateloc > -1)
			{
				string srate = r.Substring(srateloc + sstring.Length, 2);
				try
				{
					_users = double.Parse(srate) / 20;
				}
				catch (System.Exception)
				{
					Console.WriteLine("DBG: RottenTomatoes User rating parse failed..");
				}
			}
			else
			{
				//Console.WriteLine("Failed getting user rating value!");
			}
				
			
			
			// Average the two scores, convert that to a string, and return it!
			double avg = (_critic + _users) / 2;
			_retVal = avg.ToString();
			
			//Console.WriteLine("==[ RATINGS ]=================");
			//Console.WriteLine("Critics: "+_critic.ToString() + "/5");
			//Console.WriteLine("Users: "+_users.ToString() + "/5");
			//Console.WriteLine("Average: "+_retVal + "/5");
			
			return _retVal;
		}
	}
}
